package com.github.live.player;

import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.view.Surface;
import android.view.SurfaceHolder;

import com.github.live.util.ExecutorServiceUtil;
import com.github.live.util.LogFactory;
import com.github.livebase.player.IMediaPlayer;
import com.github.livebase.player.IMediaPlayerFactory;
import com.github.livebase.util.base.CollectionsUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

/**
 * @ClassName IJKPlayer
 * @description:
 * @author: biao532
 * @create: 2023-12-18 13:03
 * @Version 1.0
 **/
public class MultiFactoryPlayer implements IMediaPlayer {

    private PlayerEventListener playerEventListener;
    private float vLeft = 1f;
    private float vRight = 1f;
    private IMediaPlayer player;
    private Context mContext;
    private Surface surface;
    private IMediaPlayerFactory<? extends IMediaPlayer> factory;
    private BlockingQueue<IMediaPlayer> used;
    private List<IMediaPlayer> all;
    private int max;
    public MultiFactoryPlayer(Context context, IMediaPlayerFactory<? extends IMediaPlayer> factory, int maxSize) {
        this.mContext = context;
        this.factory = factory;
        this.max = maxSize < 1 ? 1 :maxSize;
        this.all = new ArrayList<>(maxSize);
        this.used = new ArrayBlockingQueue<>(maxSize);
        reset();
    }
    @Override
    public void setOption(Option option) {
        player.setOption(option);
    }

    @Override
    public void setDataSource(String path, Map<String, String> headers) {
        player.setDataSource(path, headers);
    }

    @Override
    public void setDataSource(AssetFileDescriptor fd) {
        player.setDataSource(fd);
    }

    @Override
    public void start() {
        player.start();
    }

    @Override
    public void pause() {
        player.pause();
    }

    @Override
    public void stop() {
        player.stop();
    }

    @Override
    public void prepareAsync() {
        player.prepareAsync();
    }

    @Override
    public void reset() {
        resetOld(this.player);
        try {
            if (!used.isEmpty()) {
                LogFactory.debug(MultiFactoryPlayer.class, "use a old player");
                this.player = used.take();
            }
            else if (all.size() < max) {
                LogFactory.debug(MultiFactoryPlayer.class,"create a new player");
                this.player = factory.create(mContext);
                this.all.add(player);
            }
            else {
                // 达到最大值，且都未reset完成
                LogFactory.debug(MultiFactoryPlayer.class, "no more players to use, create new player");
                this.player = factory.create(mContext);
                // 不使用阻塞，会阻塞ui线程
                //this.player = used.take();
            }
            this.player.setPlayerEventListener(this.playerEventListener);
            this.player.setVolume(vLeft, vRight);
            this.player.setSurface(this.surface);
        } catch (InterruptedException e) {
            LogFactory.warn(MultiFactoryPlayer.class, e);
        }
    }
    private void resetOld(IMediaPlayer old) {
        if (old == null) {
            return;
        }

        old.setSurface(null);
        if (!all.contains(old)) {
            old.release();
            return;
        }

        ExecutorServiceUtil.submit(()-> {
            try {
                old.reset();
                used.put(old);
            } catch (InterruptedException e) {
                LogFactory.warn("MultiFactory", e, "an error occurred during reset");
            }
        });
    }

    @Override
    public boolean isPlaying() {
        return player.isPlaying();
    }

    @Override
    public void seekTo(long time) {
        player.seekTo(time);
    }

    @Override
    public void release() {
        LogFactory.debug(MultiFactoryPlayer.class, "release player");
        CollectionsUtil.foreach(all, i ->
            i.release()
        );
        all.clear();
        used.clear();
        player = null;
        factory = null;
        surface = null;
    }

    @Override
    public long getCurrentPosition() {
        return player.getCurrentPosition();
    }

    @Override
    public long getDuration() {
        return player.getDuration();
    }

    @Override
    public int getBufferedPercentage() {
        return player.getBufferedPercentage();
    }

    @Override
    public void setSurface(Surface surface) {
        this.surface = surface;
        player.setSurface(surface);
    }

    @Override
    public void setDisplay(SurfaceHolder sh) {
        if (sh != null) {
            setSurface(sh.getSurface());
        } else {
            setSurface(null);
        }
    }

    @Override
    public void setVolume(float v1, float v2) {
        this.vRight = v2;
        this.vLeft = v1;
        player.setVolume(v1, v2);
    }

    @Override
    public void setLooping(boolean isLooping) {
        player.setLooping(isLooping);
    }

    @Override
    public void setSpeed(float speed) {
        player.setSpeed(speed);
    }

    @Override
    public float getSpeed() {
        return player.getSpeed();
    }

    @Override
    public long getTcpSpeed() {
        return player.getTcpSpeed();
    }

    @Override
    public void setPlayerEventListener(PlayerEventListener playerEventListener) {
        this.playerEventListener = playerEventListener;
        player.setPlayerEventListener(playerEventListener);
    }
}
